﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using YJKCodeBase.Math;
using YJKRevitCode.RevitObjectCompareUtility;
using YJKRevitCode.XYZUtility;

namespace YJKRevitCode.CurveUtility.LineGroupSuite
{
	public class LineGroupManger
	{
		public static Dictionary<XYZ, List<ILineGeter>> GroupLines(List<ILineGeter> inputLines, uint inputUsePrecision)
		{
			XYZEqualityComparer xyzequalityComparer = new XYZEqualityComparer();
			xyzequalityComparer.SetPrecision(inputUsePrecision);
			Dictionary<XYZ, List<ILineGeter>> dictionary = new Dictionary<XYZ, List<ILineGeter>>(xyzequalityComparer);
			foreach (ILineGeter lineGeter in inputLines)
			{
				Line useLine = lineGeter.UseLine;
				LineGroupManger.AddDic(dictionary, useLine, lineGeter, 0);
				LineGroupManger.AddDic(dictionary, useLine, lineGeter, 1);
			}
			return dictionary;
		}

		public static List<Line> GroupLinesAndLink(List<ILineGeter> inputLines, uint inputUsePrecision)
		{
			XYZEqualityComparer xyzequalityComparer = new XYZEqualityComparer();
			xyzequalityComparer.SetPrecision(inputUsePrecision);
			Dictionary<XYZ, List<ILineGeter>> dictionary = new Dictionary<XYZ, List<ILineGeter>>(xyzequalityComparer);
			foreach (ILineGeter lineGeter in inputLines)
			{
				Line useLine = lineGeter.UseLine;
				LineGroupManger.AddDic(dictionary, useLine, lineGeter, 0);
				LineGroupManger.AddDic(dictionary, useLine, lineGeter, 1);
			}
			Dictionary<ILineGeter, List<XYZ>> dictionary2 = new Dictionary<ILineGeter, List<XYZ>>();
			foreach (KeyValuePair<XYZ, List<ILineGeter>> keyValuePair in dictionary)
			{
				foreach (ILineGeter lineGeter2 in keyValuePair.Value)
				{
					if (!dictionary2.ContainsKey(lineGeter2))
					{
						dictionary2.Add(lineGeter2, new List<XYZ>
						{
							null,
							null
						});
					}
					Line useLine2 = lineGeter2.UseLine;
					int index = 0;
					if (MathUtility.LessThan(keyValuePair.Key.DistanceTo(useLine2.GetEndPoint(1)), keyValuePair.Key.DistanceTo(useLine2.GetEndPoint(0))))
					{
						index = 1;
					}
					dictionary2[lineGeter2][index] = keyValuePair.Key;
				}
			}
			List<Line> list = new List<Line>();
			foreach (KeyValuePair<ILineGeter, List<XYZ>> keyValuePair2 in dictionary2)
			{
				Line line = keyValuePair2.Key.UseLine;
				foreach (XYZ xyz in keyValuePair2.Value)
				{
					if (xyz != null)
					{
						line = CurveUtilityMethod.AdjustLineToNearPoint(line, xyz);
					}
				}
				list.Add(line);
			}
			return list;
		}

		private static void AddDic(Dictionary<XYZ, List<ILineGeter>> returnValue, Line useLine, ILineGeter oneLine, int usePointIndex)
		{
			if (!returnValue.ContainsKey(useLine.GetEndPoint(usePointIndex)))
			{
				returnValue.Add(useLine.GetEndPoint(usePointIndex), new List<ILineGeter>());
			}
			returnValue[useLine.GetEndPoint(usePointIndex)].Add(oneLine);
		}

		public static List<List<ILineGeter>> GroupLines(List<ILineGeter> inputLines, uint directionPrecision, double distanceEps)
		{
			List<List<ILineGeter>> list = new List<List<ILineGeter>>();
			XYZEqualityComparer usefirstGroupXYZComparer = new XYZEqualityComparer();
			usefirstGroupXYZComparer.SetPrecision(directionPrecision);
			IEnumerable<IGrouping<int, ILineGeter>> enumerable = from k in inputLines
			group k by usefirstGroupXYZComparer.GetHashCode(XYZUtilityMethod.Abs(k.UseLine.Direction));
			foreach (IGrouping<int, ILineGeter> source in enumerable)
			{
				list.AddRange(LineGroupManger.GroupSameLines(source.ToList<ILineGeter>(), Math.Abs(distanceEps)));
			}
			return list;
		}

		private static List<List<ILineGeter>> GroupSameLines(List<ILineGeter> inputLineGeter, double eps)
		{
			List<List<ILineGeter>> list = new List<List<ILineGeter>>();
			List<ILineGeter> list2 = new List<ILineGeter>();
			list2.AddRange(inputLineGeter);
			List<ILineGeter> list3 = new List<ILineGeter>();
			for (int i = 0; i < list2.Count; i++)
			{
				list3 = new List<ILineGeter>();
				list3.Add(list2[i]);
				for (int j = i + 1; j < list2.Count; j++)
				{
					if (MathUtility.Lessthan_Or_Equal(LineGroupManger.GetDistanceBetweenLinesMid(list2[j], list3), eps))
					{
						list3.Add(list2[j]);
						list2.RemoveAt(j);
						j--;
					}
				}
				list.Add(list3);
			}
			return list;
		}

		private static double GetDistanceBetweenLinesMid(ILineGeter inputLine, List<ILineGeter> inputLines)
		{
			List<Line> list = new List<Line>();
			foreach (ILineGeter lineGeter in inputLines)
			{
				list.Add(lineGeter.UseLine.Clone() as Line);
			}
			foreach (Line line in list)
			{
				line.MakeUnbound();
			}
			XYZ xyz = inputLine.UseLine.Evaluate(0.5, true);
			List<double> list2 = new List<double>();
			foreach (Line line2 in list)
			{
				list2.Add(line2.Project(xyz).Distance);
			}
			double result = double.MaxValue;
			if (list2.Count > 0)
			{
				result = list2.Average();
			}
			return result;
		}
	}
}
